#include <LitStdAfx.h>
#include <LitStream.h>

namespace Lit
{
	Stream::Stream( Access access ): mAccess( access ), mName("unknown"){}
	Stream::Stream( const std::string &name, Access access ) : mAccess(access), mName(name){}
	Stream::Stream( const Stream &rk ) : mAccess(rk.mAccess), mName(rk.mName){}
	Stream::~Stream(){}

	const std::string &Stream::getName() const{ return mName; }
	Stream::Access Stream::getAccess() const{ return mAccess; }
	std::ios::open_mode Stream::getStdAccess() const{ 
		std::ios_base::open_mode ret;
		if( mAccess & WriteAccess ) ret = std::ios::out;
		else ret = std::ios::in;
			
		if( mAccess & BinaryAccess ) ret |= std::ios::binary;
			
		return ret;
	}
	std::string Stream::readLine()
	{
		std::string l;
		readUntil('\n', l);
		return l;
	}
	std::string Stream::readAll()
	{ 
		std::string ret;
		ret.resize( size()+1 );
		read( size(), ret );
		return ret;
	}

	MemoryStream::MemoryStream( Access access ):Stream( access ){}
	MemoryStream::MemoryStream( const std::string &content, Access access  ) : Stream("_unknown_", access), stream(content){}
	MemoryStream::MemoryStream( const std::string &name, const std::string &content, Access access  ) : Stream(name, access), stream(content){}
	MemoryStream::MemoryStream( const MemoryStream &rk ) : Stream(rk){}
	MemoryStream::~MemoryStream(){}

	std::stringstream& MemoryStream::handle(){ return stream; }
	const std::stringstream& MemoryStream::handle() const{ return stream; }

	size_t MemoryStream::size() const{ return stream.str().size(); }
	void MemoryStream::close(){}
	bool MemoryStream::open( const std::string &name, Access access )
	{
		if( !mName.empty() )
		{
			mName = name;
			mAccess = access;
		}
		return true;
	}
	MemoryStream& MemoryStream::read( size_t num_chars, std::string & out ){ 
		out.resize( num_chars+1 );
		stream.read( &out.at(0), num_chars );
		out[num_chars] = '\0';
		return *this;
	}
	MemoryStream& MemoryStream::write( const std::string& str ){
		stream.write( &str.at(0), str.size() );
		return *this;
	}
	MemoryStream& MemoryStream::readUntil( char c, std::string & out ){
		char cur = 0;
		size_t i=0;
		while(  !eof() && (cur = stream.get()) != c )
		{
			out+=cur;
			i++;
		}
		if( !out.empty() ) out[i==0?0:(i-1)] = '\0';
		return *this;
	}
	bool MemoryStream::eof() const{ return stream.eof(); }
	bool MemoryStream::valid() const { return stream.good(); }

	FileStream::FileStream( ):Stream( ){}
	FileStream::FileStream( const std::string &name, Access access ) : Stream(name){ open( name, access ); }
	FileStream::FileStream( const FileStream &rk ) : Stream(rk){}
	FileStream::~FileStream(){}
		
	std::fstream& FileStream::handle(){ return mStream; }
	const std::fstream& FileStream::handle() const{ return mStream; }

	size_t FileStream::size() const{ return mSize; }
	void FileStream::close(){ mStream.close(); }
	bool FileStream::open( const std::string &name, Access access )
	{
		if( !name.empty() )
		{
			mName = name;
			mAccess = access;
				
			mStream.open( name.c_str(), getStdAccess() );
			if( !mStream.is_open() ) return false;
			if( access & WriteAccess )
			{
				size_t old = mStream.tellp();
				mStream.seekp( 0, std::ios::end );
				mSize = mStream.tellp();
				mStream.seekp( old, std::ios::beg );
			}
			else
			{
				size_t old = mStream.tellg();
				mStream.seekg( 0, std::ios::end );
				mSize = mStream.tellg();
				mStream.seekg( old, std::ios::beg );
			}
			return true;
		}
		return false;
	}
	FileStream& FileStream::read( size_t num_chars, std::string & out ){ 
		out.resize( num_chars+1 );
		mStream.read( &out.at(0), num_chars );
		out[num_chars] = '\0';
		return *this;
	}
	FileStream& FileStream::write( const std::string& str ){
		mStream.write( &str.at(0), str.size() );
		return *this;
	}
	FileStream& FileStream::readUntil( char c, std::string & out ){
		char cur = 0;
		size_t i=0;
		while(  !eof() && (cur = mStream.get()) != c )
		{
			out+=cur;
			i++;
		}
		if( !out.empty() ) out[i==0?0:(i-1)] = '\0';
		return *this;
	}
	bool FileStream::eof() const{ return mStream.eof(); }
	bool FileStream::valid() const { return mStream.good(); }
};